var _geometry = require('core/glm.js');
var _glm = _geometry.glm;
var _v3 = _geometry.vec3f;

var UNIT_WIDTH = 72;

function MapConf(conf) {
    this.mRow = conf.row + 2;
    this.mCol = conf.col + 2;
    this.mCount = this.mRow * this.mCol;
    this.mVisiable = 0;
    this.mStartTip = 0;
    this.mAround = [-1, -this.mCol, 1, this.mCol];// cell aroud: left, top, right, bottom
    this.mEdgeMask = [1, 2, 4, 8];

    this.mSize = new _v3();
    this.mOffset = new _v3();

    this.setup();
    this.removeEmpty(conf.empty);
    this.countEdges();
}
MapConf.prototype.getSize = function () {
    return this.mSize;
};
MapConf.prototype.getOffset = function (cell) {
    var col = cell % this.mCol;
    var row = (cell - col) / this.mCol;
    this.mOffset.set(UNIT_WIDTH * (col - 1), UNIT_WIDTH * (this.mRow - row - 2));
    return this.mOffset;
};
MapConf.prototype.countEdges = function () {
    var col = this.mCol;
    var max = this.mCount;
    var around = this.mAround;
    for (var i = col + 1; i < max; i++) {
        if (this.mCells[i] == 0) {
            continue;
        }
        this.mVisiable++;
        // found if there is empty cell around
        for (var a = 0; a < 4; a++) {
            if (this.mCells[i + around[a]] == 0) {
                this.mEdges[i + around[a]] |= this.mEdgeMask[a];
                this.mEdgeCount++;
            }
        }
    }
};
// remove empty cells
MapConf.prototype.removeEmpty = function (emptys) {
    var col = this.mCol;
    var cells = this.mCells;

    for (var i = 0, l = emptys.length; i < l; i += 2) {
        cells[(emptys[i] + 1) + (emptys[i + 1] + 1) * col] = 0;
    }
};
// setup map
MapConf.prototype.setup = function () {
    var row = this.mRow;
    var col = this.mCol;

    var outline = [];
    for (var i = 0; i < col; i++) {
        outline.push(0);
    }
    var content = [].concat(outline);
    for (var i = 1, end = col - 1; i < end; i++) {
        content[i] = 1;
    }

    // outline
    // content...
    // outline
    var cells = [].concat(outline);
    for (var i = 1, end = row - 1; i < end; i++) {
        cells = cells.concat(content);
    }
    this.mCells = cells.concat(outline);

    // create edges count
    var edges = [];
    for (var i = 0; i < row; i++) {
        edges = edges.concat(outline);
    }
    this.mEdges = edges;
    this.mEdgeCount = 0;

    // init size
    this.mSize.set(UNIT_WIDTH * (this.mCount - 2), UNIT_WIDTH * (this.mRow - 2));
};
MapConf.prototype.getString = function (cells) {
    var count = this.mRow * this.mCol;
    var col = this.mCol;
    var str = '';
    for (var i = 0; i < count; i++) {
        if (i % col == 0) {
            if (i > 0) {
                str += '\n';
            }
            str += cells[i];
        } else {
            str += ',' + cells[i];
        }
    }
    return str;
};
MapConf.prototype.toString = function () {
    return this.getString(this.mCells);
};
MapConf.prototype.getEdges = function () {
    return this.getString(this.mEdges);
};
/**
 * all cell count
 * @returns {*}
 */
MapConf.prototype.count = function () {
    return this.mCount;
};
MapConf.prototype.visiableCell = function () {
    return this.mVisiable;
};
MapConf.prototype.hasCell = function (index) {
    return this.mCells[index] > 0;
};
MapConf.prototype.getRow = function () {
    return this.mRow;
};
MapConf.prototype.getCol = function () {
    return this.mCol;
};
/**
 * called when an edge is pass through
 * @param cell
 * @param edge
 */
MapConf.prototype.edgeDiscount = function (cell, edge) {
    this.mEdgeCount--;
    this.mEdges[cell + this.mAround[edge]] &= ~this.mEdgeMask[edge];// map cell's left, top, right, bottom
};
/**
 * return edge id of map cell
 * @returns {number}
 */
MapConf.prototype.getStartEdge = function () {
    if (this.mEdgeCount == 0) {
        return -1;
    }

    var max = this.mCount;
    var m = -1;
    var cell = this.mStartTip;
    for (; cell < max; cell++) {
        var mask = this.mEdges[cell];
        if (mask > 0) {
            for (m = 0; m < 4; m++) {
                if ((mask & this.mEdgeMask[m]) > 0) {
                    break;
                }
            }
            break;
        }
    }

    // find map cell
    this.mStartTip = cell;
    return (cell + this.mAround[(m + 2) % 4]) * 4 + m;
};

module.exports = MapConf;